﻿namespace WatiNSahi
{
    using System;
    using System.Collections.Generic;

    using global::WatiN.Core;
    using global::WatiNSahi.Extensions;

    using WatiN.Core.Constraints;
    using System.Threading;
    using System.Diagnostics;

    public abstract partial class WatiNSahiTest
    {
        //public WatiNSahiTestBase()
        //{
        //    //this.CurrentBrowser = this.CreateBrowser();
        //    SetUp();
        //}

        //public virtual void Dispose()
        //{
        //    this.CurrentBrowser.Close();
        //    this.CurrentBrowser = null;
        //}

        /// <summary>
        /// Current Browser Instance
        /// </summary>
        protected Browser CurrentBrowser { get; set; }

        

        protected virtual void TearDown()
        {
            this.CurrentBrowser.Close();
            int PID =this.CurrentBrowser.ProcessID;
            Process browserProc = Process.GetProcessById(PID);
            if (!browserProc.HasExited)
                browserProc.Kill();
            this.CurrentBrowser = null;
        }

        protected virtual void SetUp()
        {
            this.CurrentBrowser = this.CreateBrowser();
        }

        protected Browser CreateBrowser()
        {
            return this.CreateBrowser(ExtensionsSettings.DefaultBrowser);
        }

        protected Browser CreateBrowser(BrowserType browserType)
        {
            switch (browserType)
            {
                case BrowserType.IE:
                    return new IE(ExtensionsSettings.CreateIEInNewProcess);
                case BrowserType.FireFox:
                    return new FireFox();
            }

            throw new NotImplementedException();
        }

        protected void GoTo(string url)
        {
            this.CurrentBrowser.GoTo(url);
        }

        protected void GoTo(Uri uri)
        {
            this.CurrentBrowser.GoTo(uri);
        }

        /// <summary>
        /// Fires JS Event. Note: jQuery may be required to fire selected event.
        /// </summary>
        /// <typeparam name="TJSEvent">JS Event</typeparam>
        /// <param name="parameters">Event parameters</param>
        protected void FireJSEventByParameters<TJSEvent>(params string[] parameters) where TJSEvent : IJSEvent, new()
        {
            this.CurrentBrowser.FireJSEventByParameters<TJSEvent>(parameters);
        }

        /// <summary>
        /// Fires JS Event using Browser as a IElementContainer. Note: jQuery is required to fire selected event.
        /// </summary>
        /// <typeparam name="TJSEvent">JS Event</typeparam>
        /// <param name="elementId">ID of the element on which event will be fired</param>
        protected void FireJSEvent<TJSEvent>(string elementId) where TJSEvent : IJSEvent, new()
        {
            this.CurrentBrowser.FireJSEvent<TJSEvent>(elementId);
        }

        /// <summary>
        /// Fires JS Event using Browser as a IElementContainer. Note: jQuery is required to fire selected event.
        /// </summary>
        /// <typeparam name="TJSEvent">JS Event</typeparam>
        /// <param name="elementClass">Class of the element on which event will be fired</param>
        protected void FireJSEventByClass<TJSEvent>(string elementClass) where TJSEvent : IJSEvent, new()
        {
            this.CurrentBrowser.FireJSEventByClass<TJSEvent>(elementClass);
        }

        /// <summary>
        /// Gets TextField text using Browser as a IElementContainer
        /// </summary>
        /// <param name="constraint">Constraint by which TextField will be searched</param>
        /// <returns>TextField text</returns>
        protected string GetText(Constraint constraint)
        {
            return this.CurrentBrowser.GetText(constraint);
        }

        /// <summary>
        /// Gets TextField text using Browser as a IElementContainer
        /// </summary>
        /// <param name="textFieldIdOrNameOrValue">ID/Name/Value by which TextField will be searched</param>
        /// <returns>TextField text</returns>
        protected string GetText(string textFieldIdOrNameOrValue)
        {
            return this.CurrentBrowser.GetText(textFieldIdOrNameOrValue);
        }

        protected TElement Get<TElement>(Constraint constraint) where TElement : Element
        {
            return this.CurrentBrowser.Get<TElement>(constraint);
        }

        protected TElement Get<TElement>(Constraint constraint, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.Get<TElement>(constraint, assert);
        }

        protected TElement Get<TElement>(string elementIdOrNameOrValue) where TElement : Element
        {
            return this.CurrentBrowser.Get<TElement>(elementIdOrNameOrValue);
        }

        protected TElement Get<TElement>(string elementIdOrNameOrValue, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.Get<TElement>(elementIdOrNameOrValue, assert);
        }

        protected TElement GetByAttribute<TElement>(string elementAttributeName, string elementAttributeValue) where TElement : Element
        {
            return this.CurrentBrowser.GetByAttribute<TElement>(elementAttributeName, elementAttributeValue);
        }

        protected TElement GetByAttribute<TElement>(string elementAttributeName, string elementAttributeValue, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.GetByAttribute<TElement>(elementAttributeName, elementAttributeValue, assert);
        }

        protected TElement GetByClass<TElement>(string elementClass) where TElement : Element
        {
            return this.CurrentBrowser.GetByClass<TElement>(elementClass);
        }

        protected TElement GetByClass<TElement>(string elementClass, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.GetByClass<TElement>(elementClass, assert);
        }

        protected TElement GetByText<TElement>(string elementText) where TElement : Element
        {
            return this.CurrentBrowser.GetByText<TElement>(elementText);
        }

        protected TElement GetByText<TElement>(string elementText, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.GetByText<TElement>(elementText, assert);
        }

        protected TElement GetByUrl<TElement>(string elementUrl) where TElement : Element
        {
            return this.CurrentBrowser.GetByUrl<TElement>(elementUrl);
        }

        protected TElement GetByUrl<TElement>(string elementUrl, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.GetByUrl<TElement>(elementUrl, assert);
        }

        protected TElement GetByUrl<TElement>(Uri uri) where TElement : Element
        {
            return this.CurrentBrowser.GetByUrl<TElement>(uri);
        }

        protected TElement GetByUrl<TElement>(Uri uri, bool assert) where TElement : Element
        {
            return this.CurrentBrowser.GetByUrl<TElement>(uri, assert);
        }

        protected IList<TElement> GetAll<TElement>(string elementIdOrNameOrValue) where TElement : Element
        {
            return this.CurrentBrowser.GetAll<TElement>(elementIdOrNameOrValue);
        }

        protected IList<TElement> GetAll<TElement>(Constraint constraint) where TElement : Element
        {
            return this.CurrentBrowser.GetAll<TElement>(constraint);
        }

        protected IList<TElement> GetAllByAttribute<TElement>(string elementAttributeName, string elementAttributeValue) where TElement : Element
        {
            return this.CurrentBrowser.GetAllByAttribute<TElement>(elementAttributeName, elementAttributeValue);
        }

        protected IList<TElement> GetAllByClass<TElement>(string elementClass) where TElement : Element
        {
            return this.CurrentBrowser.GetAllByClass<TElement>(elementClass);
        }

        protected IList<TElement> GetAllByText<TElement>(string elementText) where TElement : Element
        {
            return this.CurrentBrowser.GetAllByText<TElement>(elementText);
        }

        protected IList<TElement> GetAllByUrl<TElement>(Uri elementUri) where TElement : Element
        {
            return this.CurrentBrowser.GetAllByUrl<TElement>(elementUri);
        }

        protected IList<TElement> GetAllByUrl<TElement>(string elementUrl) where TElement : Element
        {
            return this.CurrentBrowser.GetAllByUrl<TElement>(elementUrl);
        }

        protected void Click<TElement>(Constraint constraint) where TElement : Element
        {
            this.CurrentBrowser.Click<TElement>(constraint);
        }

        protected void Click<TElement>(Constraint constraint, bool assert) where TElement : Element
        {
            this.CurrentBrowser.Click<TElement>(constraint, assert);
        }

        protected void Click<TElement>(string elementIdOrNameOrValue) where TElement : Element
        {
            this.CurrentBrowser.Click<TElement>(elementIdOrNameOrValue);
        }

        protected void Click<TElement>(string elementIdOrNameOrValue, bool assert) where TElement : Element
        {
            this.CurrentBrowser.Click<TElement>(elementIdOrNameOrValue, assert);
        }

        protected void ClickByClass<TElement>(string elementClass) where TElement : Element
        {
            this.CurrentBrowser.ClickByClass<TElement>(elementClass);
        }

        protected void ClickByClass<TElement>(string elementClass, bool assert) where TElement : Element
        {
            this.CurrentBrowser.ClickByClass<TElement>(elementClass, assert);
        }

        protected void ClickByText<TElement>(string elementText) where TElement : Element
        {
            this.CurrentBrowser.ClickByText<TElement>(elementText);
        }

        protected void ClickByText<TElement>(string elementText, bool assert) where TElement : Element
        {
            this.CurrentBrowser.ClickByText<TElement>(elementText, assert);
        }

        protected void ClickByUrl<TElement>(string url) where TElement : Element
        {
            this.CurrentBrowser.ClickByUrl<TElement>(url);
        }

        protected void ClickByUrl<TElement>(string url, bool assert) where TElement : Element
        {
            this.CurrentBrowser.ClickByUrl<TElement>(url, assert);
        }

        protected void ClickByUrl<TElement>(Uri uri) where TElement : Element
        {
            this.CurrentBrowser.ClickByUrl<TElement>(uri);
        }

        protected void ClickByUrl<TElement>(Uri uri, bool assert) where TElement : Element
        {
            this.CurrentBrowser.ClickByUrl<TElement>(uri, assert);
        }

        protected void SetText(Constraint constraint, string text, bool append = false)
        {
            this.CurrentBrowser.SetText(constraint, text, append);
        }

        protected void SetText(string textFieldIdOrNameOrValue, string text, bool append = false)
        {
            this.CurrentBrowser.SetText(textFieldIdOrNameOrValue, text, append);
        }

        protected void SetTextByClass(string textFieldClass, string text, bool append = false)
        {
            this.CurrentBrowser.SetTextByClass(textFieldClass, text, append);
        }

        protected void SetTextByText(string textFieldText, string text, bool append = false)
        {
            this.CurrentBrowser.SetTextByText(textFieldText, text, append);
        }

        protected void TypeText(Constraint constraint, string text, bool append = false)
        {
            this.CurrentBrowser.TypeText(constraint, text, append);
        }

        protected void TypeText(string textFieldIdOrNameOrValue, string text, bool append = false)
        {
            this.CurrentBrowser.TypeText(textFieldIdOrNameOrValue, text, append);
        }

        protected void SelectValue(Constraint constraint, string value)
        {
            this.CurrentBrowser.SelectValue(constraint, value);
        }

        protected void SelectValue(string selectListIdOrNameOrValue, string value)
        {
            this.CurrentBrowser.SelectValue(selectListIdOrNameOrValue, value);
        }

        protected void SelectValueByText(Constraint constraint, string text)
        {
            this.CurrentBrowser.SelectValueByText(constraint, text);
        }

        protected void SelectValueByText(string selectListIdOrNameOrValue, string text)
        {
            this.CurrentBrowser.SelectValueByText(selectListIdOrNameOrValue, text);
        }

        protected void Check(string checkBoxIdOrNameOrValue, bool check = true)
        {
            this.CurrentBrowser.Check(checkBoxIdOrNameOrValue, check);
        }

        protected void Check(Constraint constraint, bool check = true)
        {
            this.CurrentBrowser.Check(constraint, check);
        }

        protected void CheckByClass(string checkBoxClass, bool check = true)
        {
            this.CurrentBrowser.CheckByClass(checkBoxClass, check);
        }

        protected void SetTextUsingJS(string textFieldId, string text)
        {
            this.CurrentBrowser.SetTextUsingJS(textFieldId, text);
        }

        protected void SetTextByClassUsingJS(string textFieldClass, string text)
        {
            this.CurrentBrowser.SetTextByClassUsingJS(textFieldClass, text);
        }

        #region From Dropthings.Test.WatiN BrowserHelper.cs

        // TODO: Analyze the statements this Browser browser to match this.CurrentBrowser
        // Getting compilation error to change to non-generic static class 
        // So changin from this Browser browser to this.CurrentBrowser and internal static to protected

        /// <summary>
        /// Open New IE Browser with given url
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        protected Browser OpenNewBrowser(string url)
        {
            Browser browser = new IE();
            browser.ShowWindow(global::WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle.ShowNormal);
            browser.GoTo(url);
            browser.WaitForComplete();
            return browser;
        }

        protected int[] FindPosition(Element e)
        {
            var top = 0;
            var left = 0;

            var item = e;
            while (item != null)
            {
                top += int.Parse(item.GetAttributeValue("offsetTop"));
                left += int.Parse(item.GetAttributeValue("offsetLeft"));

                item = item.Parent;
            }

            return new int[] { left, top };
        }

        /// <summary>
        /// Wait for Async Post Back Complete
        /// </summary>
        /// <param name="timeout"></param>
        /// <returns></returns>
        protected bool WaitForAsyncPostbackComplete(int timeout)
        {
            int timeWaitedInMilliseconds = 0;
            var maxWaitTimeInMilliseconds = Settings.WaitForCompleteTimeOut * 1000;
            var scriptToCheck = "Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack();";

            while (bool.Parse(this.CurrentBrowser.Eval(scriptToCheck)) == true
                    && timeWaitedInMilliseconds < maxWaitTimeInMilliseconds)
            {
                Thread.Sleep(Settings.SleepTime);
                timeWaitedInMilliseconds += Settings.SleepTime;
            }

            return bool.Parse(this.CurrentBrowser.Eval(scriptToCheck));
        }

        /// <summary>
        /// Wait for JQuery Ajax Request
        /// </summary>
        protected void WaitForJQueryAjaxRequest()
        {
            int timeWaitedInMilliseconds = 0;
            var maxWaitTimeInMilliseconds = Settings.WaitForCompleteTimeOut * 1000;

            // TODO: Changed below line from browser.Is.... to Is..(browser) need to analyse
            while (IsJQueryAjaxRequestInProgress()
                    && timeWaitedInMilliseconds < maxWaitTimeInMilliseconds)
            {
                Thread.Sleep(Settings.SleepTime);
                timeWaitedInMilliseconds += Settings.SleepTime;
            }
        }

        private bool IsJQueryAjaxRequestInProgress()
        {
            var evalResult = this.CurrentBrowser.Eval("watinAjaxMonitor.isRequestInProgress()");
            return evalResult == "true";
        }

        // Removing this Browser browser and changing to this.CurrentBrowser and changing from internal static to private
        private void InjectJQueryAjaxMonitor()
        {
            const string monitorScript =
                @"function AjaxMonitor(){"
                + "var ajaxRequestCount = 0;"

                + "$(document).ajaxStart(function(){"
                + "    ajaxRequestCount++;"
                + "});"

                + "$(document).ajaxComplete(function(){"
                + "    ajaxRequestCount--;"
                + "});"

                + "this.isRequestInProgress = function(){"
                + "    return (ajaxRequestCount > 0);"
                + "};"
                + "}"

                + "var watinAjaxMonitor = new AjaxMonitor();";

            this.CurrentBrowser.Eval(monitorScript);
        }

        private static void ClearCookiesInIE()
        {
            Process.Start("RunDll32.exe", "InetCpl.cpl,ClearMyTracksByProcess 2").WaitForExit();
        }

        private static void DeleteEverythingInIE()
        {
            Process.Start("RunDll32.exe", "InetCpl.cpl,ClearMyTracksByProcess 255").WaitForExit();
        }

        private void ClearCookies()
        {
            ClearCookiesInIE();
        }


        #endregion



    }
}
